<?php
/**
 * Eka Framework 0.3.0
 *
 * @copyright Copyright (c) 2008 Alexey Yu. Chuprina <656b61@gmail.com> (http://php-eka.googlecode.com)
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 *
 * @version $Id$
 */

require_once 'Eka/Db/Adapter/Abstract.php';

require_once 'Eka/Db/Statement/Pdo.php';

/**
 * Eka_Db_Adapter_Pdo_Abstract
 *
 * @package Db
 * @subpackage Adapter
 */
abstract class Eka_Db_Adapter_Pdo_Abstract extends Eka_Db_Adapter_Abstract
{
	/**
	 * PDO type
	 *
	 * @var string
	 */
	protected $pdoType = null;
	
	/**
	 * Creates a PDO object and connects to the database
	 *
	 * @return void
	 */
	protected function connect()
	{
		if (null !== $this->connection) {
			return;
		}

		// dns
		$dsn = array();
		$dsn[] = 'host=' . $this->host;
		$dbName = $this->getConfigValue(self::CONFIG_DBNAME);
		if (null !== $dbName) {
			$dsn[] = 'dbname=' . $dbName;
		}
		$dsn =  $this->pdoType . ':' . implode(';', $dsn);

		// check for PDO extension
		if (!extension_loaded('pdo')) {
			include_once 'Eka/Db/Adapter/Exception.php';
			throw new Eka_Db_Adapter_Exception('The PDO extension is required for this adapter but the extension is not loaded');
		}

		// check the PDO driver is available
		if (!in_array($this->pdoType, PDO::getAvailableDrivers())) {
			include_once 'Eka/Db/Adapter/Exception.php';
			throw new Eka_Db_Adapter_Exception("The '{$this->pdoType}' PDO driver is not currently installed");
		}

		try {
			$this->connection = new PDO($dsn, $this->username, $this->password, $this->getConfigValue(self::CONFIG_DRIVER_OPTIONS));

			// always use exceptions
			$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

		} catch (PDOException $e) {
			include_once 'Eka/Db/Adapter/Exception.php';
			throw new Eka_Db_Adapter_Exception($e->getMessage(), $e);
		}

		if (null !== $this->charset) {
			$this->query("SET NAMES '{$this->charset}'");
		}
	}

	/**
	 * Force the connection to close
	 *
	 * @return void
	 */
	public function closeConnection()
	{
		$this->connection = null;
	}

	/**
	 * Prepares an SQL statement
	 *
	 * @param string $sql The SQL statement with placeholders
	 * @param array $bind An array of data to bind to the placeholders
	 * @return Eka_Db_Statement_Pdo
	 */
	public function prepare($sql)
	{
		$this->connect();
		return new Eka_Db_Statement_Pdo($this, $sql);
	}

	/**
	 * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column
	 *
	 * @return string
	 */
	public function getLastInsertId()
	{
		$this->connect();
		return $this->connection->lastInsertId();
	}

	/**
	 * Special handling for PDO query()
	 *
	 * All bind parameter names must begin with ':'
	 *
	 * @param string $sql The SQL statement with placeholders
	 * @param array $bind An array of data to bind to the placeholders
	 * @return Eka_Db_Statement_Pdo
	 * @throws Eka_Db_Adapter_Exception To re-throw PDOException
	 */
	public function query($sql, $bind = null)
	{
		if (is_array($bind)) {
			foreach ($bind as $name => $value) {
				if (!is_int($name) && $name[0] != ':') {
					unset($bind[$name]);
					$bind[':' . $name] = $value;
				}
			}
		}

		try {
			return parent::query($sql, $bind);
		} catch (PDOException $e) {
			include_once 'Eka/Db/Adapter/Exception.php';
			throw new Eka_Db_Adapter_Exception($e->getMessage(), $e);
		}
		return null; // чтоб зенд струдио не давал варнинг
	}

	/**
	 * Quote a raw string
	 *
	 * @param string $value
	 * @return string
	 */
	protected function doQuote($value)
	{
		if (is_int($value) || is_float($value)) {
			return $value;
		}
		$this->connect();
		return $this->connection->quote($value);
	}

	/**
	 * Begin a transaction
	 */
	protected function doBeginTransaction()
	{
		$this->connect();
		$this->connection->beginTransaction();
	}

	/**
	 * Commit a transaction
	 */
	protected function doCommit()
	{
		$this->connect();
		$this->connection->commit();
	}

	/**
	 * Roll-back a transaction
	 */
	protected function doRollBack() {
		$this->connect();
		$this->connection->rollBack();
	}
}